package com.wxg.print;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import com.wxg.entity.EleIdAndBounds;
import com.wxg.entity.MyPage;
import com.wxg.entity.MyPages;
import com.wxg.entity.WebEleBounds;
import com.wxg.utils.My;
import com.wxg.utils.MyDriver;
import com.wxg.utils.MyFileReader;
import com.wxg.utils.MyFileWriter;

/**
 * @see com.wxg.demo.Emr102
 * @see com.wxg.demo.Emr103
 * 
 * @author Wxg
 * 在看了输出的结果后,我越来越觉得应该在编写模板时加以控制(即在百度UE上下功夫)
 * -	* 如果前台(UE)没有界限,模板制作人员或用户将随意输入内容. 有些明显可以规避的问题也没法注意到!
 * -	* 如果在前台有明显的界限,模板制作人员可以主动控制表格的高度,主动添加分页,调整格式的美观度!
 * table分割
 * -	* 直接按tr分割
 * -	* 遍历tr中的每个td, 将每个td的内容也进行分割
 *
 */
public class GenHtmlForPrint {
	/**
	 * div[class="emr_main"] 的高度
	 */
	public static final int MAIN_HEIGHT = 940;
	
	/**
	 * 暂时未使用
	 * 如果元素的高度小于 MIN_H, 直接输出到下一个页面!( 不拆分这个元素 )
	 */
	public static final int MIN_H = 20;
	
	/**
	 * 添加id后存储到本地的html文件的地址
	 */
	private String genFilepath;
	
	/**
	 * 每页应该输出的block元素的id集合
	 */
	private MyPages pages;
	
	/**
	 * 如果源是一个html文件,将使用此变量存储
	 */
	private String sourceHtmlpath;
	
	/**
	 * 源是一个html字符串
	 * 这种情况更符合正式项目的逻辑(源html从百度UE发送过来)
	 */
	private String sourceHtmlStr;
	
	public static enum HtmlSourceType {
		HtmlFile, HtmlStr
	}
	private HtmlSourceType htmlSourceType;
	
	private String idPrefix; // id前缀(id_)
	
	/**
	 * 增加一个source属性
	 * (sourceHtmlpath, sourceHtmlStr, sourceFile)
	 * 
	 */
	private File sourceFile;
	
	/**
	 * 存储跨页元素
	 */
	private List<EleIdAndBounds> blockOverPageList;
	
	
	public GenHtmlForPrint(String source, HtmlSourceType type){
		this.htmlSourceType = type;
		if(type == HtmlSourceType.HtmlFile){
			sourceHtmlpath = source;
		}
		if(type == HtmlSourceType.HtmlStr){
			sourceHtmlStr = source;
		}
	}
	
	public GenHtmlForPrint(File file){
		this.sourceFile = file;
	}
	
	/**
	 * 添加id属性,存储文件,保存文件地址
	 * idea: 应该将block元素的outerHTML保存起来(那样的话,验证block...)
	 * -	* 应该只提取body的一级子元素是block的情况
	 * 
	 * @param sourceFilepath
	 */
	public void storeHtmlWithGenId(String idPrefix){
		this.idPrefix = idPrefix;
		Document doc = null;
		
		if(null != sourceFile){
			try {
				doc = Jsoup.parse(sourceFile, "UTF-8");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else if(htmlSourceType == HtmlSourceType.HtmlFile){
			try {
				doc = Jsoup.parse(new File(sourceHtmlpath), "UTF-8");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else{
			doc = Jsoup.parse(sourceHtmlStr);
		}
		
		if(null != doc){
			Element body = doc.body();
			Elements eles = body.getAllElements();
			int id = 1;
			for(Element ele : eles){
				if(!"body".equalsIgnoreCase(ele.tagName())){
					if(ele.isBlock()){
						ele.attr("id", idPrefix + (id++));
					}
				}
			}
			
			MyFileWriter myw = new MyFileWriter(); // 无参构造方法将使用默认的存储地址
			myw.writeb( doc.toString() );
			myw.close();
			genFilepath = myw.getFilepath();
		}
	}
	
	public void storeHtmlWithGenId(){
		storeHtmlWithGenId("id_");
	}

	public String getIdPrefix() {
		return idPrefix;
	}
	
	/**
	 * 
	 * 
	 * @see com.wxg.demo.HowManyBlockTags
	 * tbody, tr, td 要去除, 它们是一个整体,属于 table
	 * 
	 * update : table, tr 筛选出来
	 * 
	 * @param url
	 * @return
	 */
	public List<EleIdAndBounds> getBlockEleBounds(){
		String url = My.fileUrl( genFilepath );
		List<EleIdAndBounds> retList = new ArrayList<EleIdAndBounds>();

		WebDriver driver = MyDriver.getStaticDriver();
		driver.get( url );
		String strXpath = "//*[starts-with(@id,'id_')]";
		strXpath = "//*[starts-with(@id,'" + idPrefix + "')]";
		List<WebElement> list = driver.findElements(By.xpath( strXpath ));

		String[] exceptArr = {"tbody", "tr", "td"};
		
		if (null != list) {
			for (WebElement ele : list) {
				if(My.notIn(ele.getTagName(), exceptArr)){
					Dimension d = ele.getSize();
					Point p = ele.getLocation();
					WebEleBounds bounds = new WebEleBounds(p.x, p.y, d.width, d.height);
					retList.add( new EleIdAndBounds(ele.getAttribute("id"), bounds) );
				}
			}
		}

		/**
		 * 这里并没有调用`driver.quit`, 是延迟到之后的某一个时刻再调用. 使得driver能够得到重用!
		 */
		return retList;
	}
	
	/**
	 * 不使用`bounds.y+height`, 直接使用`height`
	 * 
	 * @param url
	 * @return
	 */
	public List<EleIdAndBounds> whosOverPage(){
		blockOverPageList = new ArrayList<EleIdAndBounds>();
//		List<EleIdAndBounds> list = new ArrayList<EleIdAndBounds>();
		
		List<EleIdAndBounds> ibList = getBlockEleBounds();
		
		int len = ibList.size();
		int height = 0;
		int previousHeight = 0;
		
		pages = new MyPages();
		MyPage page = pages.newPage();
		for(int i=0; i<len; i++){
			EleIdAndBounds ib = ibList.get(i);
			previousHeight = height;
			height += ib.bounds.height;
			if( height > MAIN_HEIGHT ){
				// if( ib.bounds.height <= MIN_H ){  } // 不添加到list中!
				
				/**
				 * 只在`whosOverPage`方法中的"EleIdAndBounds"元素有设置这个值
				 * 用来将块元素分割成行元素时做辅助(参考)
				 */
				ib.setStartHeightInPage(previousHeight); 
				
				blockOverPageList.add( ib ); // 当前元素
				height = ib.bounds.height; // 重新开始计算
				page = pages.newPage();
			}
			page.add(ib.id);
		}
		return blockOverPageList;
	}
	
	/**
	 * 插入pageHeader,pageFooter
	 * @see com.wxg.demo.Emr101
	 * 
	 * 
	 */
	public String insertHeaderAndFooter(){
		
		Document doc = null;
		try {
			doc = Jsoup.parse(new File(genFilepath), "UTF-8");
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		// writer
		MyFileWriter writer = new MyFileWriter("html_");
		
		writer.writeb("<html>");
		
		// head
		writer.writeb("<head>");
		
		// 提取原html中的head内容
		if(null != doc){
			Element head = doc.getElementsByTag("head").get(0);
			for(Element ele : head.children()){
				writer.writeb( ele.outerHtml() );
			}
		}
		
		//加入自己的style(放在后面)
		MyFileReader mfr = new MyFileReader("com/wxg/html/a102/mystyle.html");
		for(String str : mfr.list()){
			writer.writeb(str);
		}
		writer.writeb("</head>");
		// body
		writer.writeb("<body>");
		
		if(null != doc){
			int i = 1; // 页码
			for(MyPage page : pages.getPages()){
				// page_header : 要放到page循环中
				mfr = new MyFileReader("com/wxg/html/a102/pageHeader.html");
				for(String str : mfr.list()){
					writer.writeb(str);
				}
				
				for(String id : page.getIds()){
					writer.writeb( doc.getElementById(id).outerHtml() );
				}
				
				// page_footer : 要放到page循环中
				mfr = new MyFileReader("com/wxg/html/a102/pageFooter.html");
				for(String str : mfr.list()){
					if(str.contains("{{page}}")){
						str = str.replace("{{page}}", i+"");
					}
					writer.writeb(str);
				}
				i++;
			}
		}
		
		writer.writeb("</body>");
		
		writer.writeb("</html>");
		
		// writer close
		writer.close();
		return writer.getFilepath();
	}
	
	public String genHtml(){
		storeHtmlWithGenId();
		whosOverPage(); // 在`whosOverPage()`内部调用`getBlockEleBounds()`
		return insertHeaderAndFooter();
	}
	
	/**
	 * 
1517999292265
1517999297903 (5638)
1517999301053 (3150)
1517999303803 (2750)
1517999306259 (2456)
1517999310241 (3982)
1517999312887
1517999315573
1517999318309
1517999321081
1517999324997
1517999328465
1517999331169
1517999333859
1517999336690
1517999339440
1517999342094
1517999344728
1517999347497
1517999350558
1517999354730
1517999354828
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		GenHtmlForPrint ghfp = null;
		System.out.println( System.currentTimeMillis() );
		String dirpath = "F:\\wxg\\for_print\\myjfserver\\src\\main\\webapp\\uehtml";
		File dir = new File(dirpath);
		for(File file : dir.listFiles()){
			ghfp = new GenHtmlForPrint(file);
			System.out.println( ghfp.genHtml() );
			System.out.println( System.currentTimeMillis() );
		}
		// String filepath = dirpath + "\\html_102.html";
		MyDriver.closeStaticDriver();
	}
	
}
